/**
 * 以后这些函数库全部都需要载入
 * 加油吧小伙伴们 by Mike/大当家
 */


//
// let os = com.far.x.utils.script.OsKit;
// let Worker = java.lang.Thread;


//方便其他文件自动提示，本质上在这儿没有作用
let __DIR__;
let thisObject;

/**
 * 默认存redis
 * @param ob
 */
function saveObject(ob) {
    let keys = Object.keys(ob);
    //声明父类继承下来的属性需要存储到的地方
    ob.data["__attr__"] = {};
    for (let k in keys) {
        if (keys[k].startsWith("_")) {
            //__这种开头的是否需要存储？
            //凡是_开头的都是父类属性，子类都要存储
            ob.data["__attr__"][keys[k]] = ob[keys[k]];
        }
    }
    return os.cache.save(ob.get("dtable"), ob.get("id"), JSON.stringify(ob.data));
}

function restoreObject(ob) {
    let data = os.cache.restore(ob.get("dtable"), ob.get("id"));
    data = JSON.parse(data);
    let keys = Object.keys(data.__attr__);
    //装载属性
    for (let e in keys) {
        let key = keys[e];
        ob[key] = data.__attr__[key];
    }
    //删除读取的属性
    delete data["__attr__"];
    ob.data = data;
    return ob;
}

function environment() {
    let args = arguments;
    if (args.length == 1) {
        //environment(ob)
        let ob = args[0];
        if (undefinedp(ob.get("env"))) return false;
        //加上参数1 是按xxxx.js#12 查找
        return loadObject(ob.get("env"), 1);
    } else if (args.length <= 0) {
        return loadObject(ob.get("env"), 1);
    }
    return false;
}


/**
 * 获取对象的内容物
 * 如果这个对象身上还挂着内容的文件地址，就重新加载
 * @param ob
 */
function allInventory(ob) {
    let ins = ob.get("inventorys");
    let objs = [];
    for (let e in ins) {
        objs.push(loadObject(ins[e], 1));
    }
    return objs;
}

/**
 * 名称
 present() - 通过 id 查找对象
 语法
 object present( object | string str );
 object present( object | string str, object ob );
 描述
 如果第一个参数是字符串，第二个参数为 0 或不指定，在当前对象的内容对象中和当前对象所在环境的的内容对象中寻找对象的 id() 方法返回值为 1 的对象，找到后返回该对象。

 如果第一个参数是字符串，第二个参数是对象，仅仅在指定对象的内容对象中寻找。

 如果第一个参数是对象，第二个参数为 0 或不指定，检查对象 `str` 是否在当前对象的环境中或当前对象所在的环境中，如果是，返回对象 `str` 的环境。

 如果第一个参数和第二个参数都是对象，检查第一个对象是否在第二个对象中，如果是，返回第一个对象。

 如果要查找的对象是隐藏的（通过 set_hide() 外部函数），而当前对象不可隐藏，查找结果返回 0。
 * @returns {[]}
 */
function present() {


    if (arguments.length == 2) {
        if (!objectp(arguments[1])) {
            tellObject(thisObject, `the second argument to the present method must be an object got ${typeof arguments[1]}`);
            return;
        }
        let inObs = allInventory(arguments[1]);

        if (!arrayp(inObs)) return false;
        if (inObs.length <= 0) return false;

        let result = inObs.filter((e) => {

            //我日 这儿的e是对象。。。注意...
            let ob = loadObject(fileNameSid(e), 1);
            if (objectp(ob) && ob.get("id") == arguments[0]) {
                return ob;
            }
        });
        return result.length > 0 ? result[0] : false;
    }
}


function jsonp(obj) {
    return typeof (obj) == "object" && Object.prototype.toString.call(obj).toLowerCase() == "[object object]" && !obj.length;
}

////判断方式 https://www.cnblogs.com/yadiblogs/p/10750775.html
function arrayp(e) {
    return Object.prototype.toString.call(e) === '[object Array]';
}


function moveObject(source, dest) {
    if (undefinedp(dest.get("inventorys"))) {
        dest.set("inventorys", []);
    }

    dest.get("inventorys").push(fileNameSid(source));
    source.set("env", fileNameSid(dest));
    return true;
}


function newObj() {
    let arg = arguments;
    if (arg.length == 2) {
        //arg 1是配置文件
        let obj = os.create(arg[0]),
            {datas} = os.importx(arg[1]);
        let dueKey = Object.keys(datas.due),
            tempKey = Object.keys(datas.temp);
        for (let dk in dueKey) {
            obj.set(dueKey[dk], datas.due[dueKey[dk]])
        }
        for (let tk in tempKey) {
            obj.set(tempKey[tk], datas.temp[dueKey[dk]])
        }
        return obj;
    } else if (arg.length == 1) {
        return createObject(arg[0]);
    }
}

// function newObj() {
//     let arg = arguments;
//     if (arg.length == 2) {
//         //arg 1是配置文件
//         let obj = os.create(arg[0]),
//             {datas} = os.importx(arg[1]);
//         let dueKey = Object.keys(datas.due),
//             tempKey = Object.keys(datas.temp);
//         for (let dk in dueKey) {
//             obj.set(dueKey[dk], datas.due[dueKey[dk]])
//         }
//         for (let tk in tempKey) {
//             obj.set(tempKey[tk], datas.temp[dueKey[dk]])
//         }
//         return obj;
//     } else if (arg.length == 1) {
//         return os.create(arg[0]);
//     }
// }


// function loadScriptToText(file) {
//     let gt = os.getGlobalThis();
//     os.fs.readFileSync(file, function (err, data) {
//         if (err != "") {
//             os.debug(err);
//             return;
//         }
//         let src = uint8ArrayToString(data);
//         gt.metaClassSource.set(file, src);
//     });
//
// }

function loadScriptToCmplObj(file) {
    let gt = os.getGlobalThis();
    os.fs.readFileSync(file, function (err, data) {
        if (err != "") {
            os.debug(err);
            return;
        }
        let src = uint8ArrayToString(data);
        let cmpl = os.vm.cmpl(src, file);
        gt.metaClassSource.push({file: file, cmpl: cmpl, src: ""});
    });

}


function findMetaClass(file) {
    let gt = os.getGlobalThis();
    let result = gt.metaClassSource.filter(e => {
        return e.file == file;
    });
    return result.length > 0 ? result[0] : false;
}


function loadMetaClass(file) {
    let gt = os.getGlobalThis();
    //gameObjects  metaClassSource
    if (!jsonp(findMetaClass(file))) {
        //不存在类模板就加载类模板
        loadScriptToCmplObj(file);
    }
    return findMetaClass(file);
}

/**
 * 复制对象引用的公共方法
 * 递归复制
 * @param ob
 */
function copyAllIncludes(ob) {
    //手工暴力copy
    if ("includes" in ob) {
        ob.includes.forEach(e => {

            let cls = loadMetaClass(e);
            let incOb = os.vm.exec(cls.cmpl, e);
            //还有就继续递归。。。。
            if ("includes" in incOb) {
                copyAllIncludes(incOb);
            }
            let attrKeys = Object.keys(incOb);
            for (let k in attrKeys) {
                let key = attrKeys[k];
                // os.debug( functionp( incOb[key]),"属性的类型是" );
                if (key == "__DIR__") continue;
                if (key == "thisObject") continue;
                ob[key] = incOb[key];
            }
        })
    }
}


function copyAllInherits(ob, sunOb) {
    //手工暴力copy
    if ("inherits" in ob) {
        ob.inherits.forEach(e => {

            let cls = loadMetaClass(e);
            let incOb = os.vm.exec(cls.cmpl, e);

            //被继承的对象也是有includes的...
            copyAllIncludes(incOb);
            if ("inherits" in incOb) {
                copyAllInherits(incOb, sunOb);
            }
            //父类写入指向子类的指针
            incOb["thisObject"] = sunOb;

            let attrKeys = Object.keys(incOb);

            for (let k in attrKeys) {
                let key = attrKeys[k];
                if (key == "__DIR__") continue;
                if (key == "thisObject") continue;
                ob[key] = incOb[key];
            }
        })
    }
    //  os.debug(ob,"debuger");
}


/**
 *
 *
 *  根据文件名
 *  寻找内存中的对象，没有就新建一个对象返回
 *  该方法永远会返回一个对象，除非传入的文件不存在
 *  所以她可以作为findObject使用
 *  假定 传入的参数
 *  x/user.js
 *  x/user.js#123
 *
 *    type等于2时，传入的一定是   x/user.js#123

 所以 是两种查找方式 一种是模糊查找 一种是精准查找
 模糊查找
 loadObject("adm/daemons/master.js");
 精准查找
 loadObject("clone/user.js#123",1);
 *
 *
 *  @author Mike/Fang.j/大当家
 *
 */
function loadObject() {


    let type, file;

    type = arguments.length > 1 ? 2 : 1;

    file = arguments[0];

    let obs = getObjects();

    let result = obs.filter(e => {

        if (type == 2 && e.__fileName__ == file) {
            return e;
        }
        if (type == 1 && e.__fileName__.indexOf(file) > -1) {
            return e;
        }
    });

    //如果没有，就加载对象....
    let files = [];
    if (result.length <= 0) {
        file = type == 1 ? file + "#" : file;
        files = file.split("#");
        loadMetaClass(files[0]);
        result[0] = newObj(files[0]);
    }


    return result.length > 0 ? result[0] : false;
}


function addObjectToGame(ob) {
    let gt = os.getGlobalThis();

    if (undefinedp(gt.gameObjects)) {
        gt["gameObjects"] = [];
    }

    gt.gameObjects.push(ob);
}

function createObject(file) {

    let gt = os.getGlobalThis();

    let clazz = loadMetaClass(file);
    let ob = os.vm.exec(clazz.cmpl, file);

    //构造对象的基本参数
    ob["meScript"] = file;
    //数据存储属性
    ob["data"] = {__dataTemp__: {}};

    ob["__baseFileName__"] = file;
    ob["__fileName__"] = file + "#" + os.util.random.randomSid();

    let dir, arrs = file.split("/");

    if (arrs.length > 0) {
        arrs.length = arrs.length - 1;
    }
    dir = arrs.join("/");

    ob["__DIR__"] = dir + "/";
    //指向自己
    ob["thisObject"] = ob;

    ob["os"] = os;

    //卧槽，，又要处理继承关系和include文件.....

    //  os.debug(JSON.stringify(ob), "看下继承文件");
    copyAllIncludes(ob);
    copyAllInherits(ob, ob);
    if (!"create" in ob) {
        os.debug("NewObj failed. The object has no create method");
        return;
    }

    if ("create" in ob) {
        ob.create();
        //必须放在load前面
        addObjectToGame(ob);
        loadObject("adm/daemons/master/master.js").validObjectAfter(ob);

    }


    return ob;
}


// function tellObject(ob, msg) {
//     os.tellObject(ob, msg + "\n");
// }


function tellObject(ob, msg) {

    let Warp = function (ob,msg) {
        this.msg = msg;
        this.ob = ob;
        this.to = function () {
            this.msg += "\n";
            if (this.ob.get("obType") == "isPlayer") {
                this.ob.get("agent").getSession().sendText(this.msg);
            } else if (this.ob.get("obType") == "isAgent") {
                //直接就是session对象;
                this.ob.getSession().sendText(this.msg);
            }

        }
    }
    let warp = new Warp(ob,msg);

    // msg += "\n";
    // if (ob.get("obType") == "isPlayer") {
    //     ob.get("agent").getSession().sendText(msg);
    // } else if (ob.get("obType") == "isAgent") {
    //     //直接就是session对象;
    //     ob.getSession().sendText(msg);
    // }
    return warp;


}


function findPlayer(arg) {
    let obs = os.getObjects();
    for (let k in obs) {
        let ob = obs[k];
        //对象列表中，并不是所有对象都实现了get和Set方法,要判断一下
        if ("get" in ob) {
            if (ob.get("obType") != "" && ob.get("obType") == "isPlayer") {
                if (ob.get("id") == arg) {
                    return ob;
                }
            }
        }
    }
    return false;
}

function userp(ob) {
    if (undefinedp(ob.get("obType"))) return false;
    return ob.get("obType") == "isPlayer" ? true : false;
}

function getObjects() {

    let gt = os.getGlobalThis();
    if (!arrayp(gt["gameObjects"])) return [];

    let objs = gt["gameObjects"].filter(e => {
        //过滤掉没有get方法的对象，这种对象一般都有问题..注意观察
        if (undefinedp(e.get)) {
            // os.debug("this object not find <get>");
        } else {
            return e;
        }
    })


    return objs;
}

/**
 * 约定只有对象和Json对象才是object
 * string false undefined int number doubel 都不是....
 * @param ob
 * @returns {*}
 * @author mike/Fang.j/大当家
 */
function objectp(ob) {
    return os.objectp(ob);
}

function functionp(ob) {
    return typeof ob == "function";
}


function stringp(ob) {
    let type = Object.prototype.toString.call(ob);
    if (type == "[object String]") return true;
    return false;
}

//获取所有的玩家，包括连接已经断开的玩家

function getUsers() {


    let objs = getObjects();
    if (!arrayp(objs)) return [];

    let ret = [];

    objs.forEach((e) => {
        // os.debug(e,"debuger");
        if (!undefinedp(e.get) && e.get("obType") == "isPlayer") {
            ret.push(e);
        }

        // if( e.get("obType") == "isPlayer" ){
        //     ret.push(e);
        // }
    });
    return ret;
}

function getUser(account) {
    let obs = getUsers();
    for (let e in obs) {
        if (obs[e].get("account") == account) {
            return obs[e];
        }
    }
    return 0;
}


/**
 *
 * 一个参数时，按照 <文件名> 查找
 * 2个参数时，按照  <文件名#123> 查找
 *
 * @returns {boolean|*}
 * @constructor
 */
function D() {

    let arg = arguments;

    if (arg.length > 0 && !stringp(arg[0])) {
        os.debug("the first argument must be a string");
        return;
    }


    if (arg.length == 1) {
        return os.D(arg[0]);
    } else if (arg.length == 2) {
        //找不到就创建新的...
        return os.D(arg[0], arg[1]);
    }
    return false;

}

/**
 *
 * @param u user
 * @param a agent
 */
function confix(u, a) {
    u.set("agent", a);
    a.setUser(u);
}

//占时不处理
function notifyFail(str) {

}


function undefinedp(val) {

    if( val=="undefined" ) return true;

    return typeof (val) == "undefined";
}


function baseFileName(ob) {
    return ob.__baseFileName__;
}


function fileNameSid() {
    let arg = arguments;
    if (arg.length <= 0) {
        return thisObject.__fileName__;
    } else if (arg.length == 1) {
        return arg[0].__fileName__;
    }
}

//-----------------------------------------------------------------------------
/**
 * 在一个区间生成随机数
 * @param min
 * @param max
 * @returns {number}
 */
function rangeRondom(min, max) {
    return Math.floor(Math.random() * (max - min + 1) + min);
}

/**
 * 深拷贝
 * @param obj
 * @returns {*[]}
 */
function deepClone(obj) {
    let objClone = Array.isArray(obj) ? [] : {};
    if (obj && typeof obj === "object" && obj.hasOwnProperty) {
        for (key in obj) {
            if (obj.hasOwnProperty(key)) {
                //判断ojb子元素是否为对象，如果是，递归复制
                if (obj[key] && typeof obj[key] === "object") {
                    objClone[key] = deepClone(obj[key]);
                } else {
                    //如果不是，简单复制
                    objClone[key] = obj[key];
                }
            }
        }
    }
    return objClone;
}


/**
 * 随机从一个数组里面抽取一个元素
 * @param arr
 * @returns {*}
 */
function getRandomOneOfArr(arr) {
    return arr[Math.floor(Math.random() * arr.length)];
}


/**
 * 数字货币转换
 * @param value
 * @returns {string}
 */
function transformNumToCh(value) {
    let newValue = ['', '', ''];
    let fr = 1000;
    const ad = 1;
    let num = 3;
    let fm = 1;
    while (value / fr >= 1) {
        fr *= 10;
        num += 1;
        console.log('数字', value / fr, 'num:', num);
    }
    if (num <= 4) { // 千
        newValue[1] = '千';
        newValue[0] = parseInt(value / 1000) + '';
    } else if (num <= 8) { // 万
        let text1 = parseInt(num - 4) / 3 > 1 ? '千万' : '万';
        // tslint:disable-next-line:no-shadowed-variable
        fm = '万' === text1 ? 10000 : 10000000;
        newValue[1] = text1;
        newValue[0] = (value / fm) + '';
    } else if (num <= 16) {// 亿
        let text1 = (num - 8) / 3 > 1 ? '千亿' : '亿';
        text1 = (num - 8) / 4 > 1 ? '万亿' : text1;
        text1 = (num - 8) / 7 > 1 ? '千万亿' : text1;
        // tslint:disable-next-line:no-shadowed-variable
        let fm = 1;
        if ('亿' === text1) {
            fm = 100000000;
        } else if ('千亿' === text1) {
            fm = 100000000000;
        } else if ('万亿' === text1) {
            fm = 1000000000000;
        } else if ('千万亿' === text1) {
            fm = 1000000000000000;
        }
        newValue[1] = text1;
        newValue[0] = parseInt(value / fm) + '';
    }
    if (value < 1000) {
        newValue[1] = '';
        newValue[0] = value + '';
    }
    return newValue.join('');
}

/**
 * 后面优化
 * @returns {*}
 */
function sprintf() {
    var s = arguments[0];
    for (var i = 0; i < arguments.length - 1; i++) {
        var reg = new RegExp("\\{" + i + "\\}", "gm");
        s = s.replace(reg, arguments[i + 1]);
    }
    return s;
}

function uint8ArrayToString(fileData) {

    return utf8ArrayToStr(fileData);

}


/* utf.js - UTF-8 <=> UTF-16 convertion
*
* Copyright (C) 1999 Masanao Izumo <iz@onicos.co.jp>
* Version: 1.0
* LastModified: Dec 25 1999
* This library is free.  You can redistribute it and/or modify it.
* 1999年 日本人就再玩这些了，国人加油！
*
*/

function utf8ArrayToStr(array) {
    var out, i, len, c;
    var char2, char3;

    out = "";
    len = array.length;
    i = 0;
    while (i < len) {
        c = array[i++];
        switch (c >> 4) {
            case 0:
            case 1:
            case 2:
            case 3:
            case 4:
            case 5:
            case 6:
            case 7:
                // 0xxxxxxx
                out += String.fromCharCode(c);
                break;
            case 12:
            case 13:
                // 110x xxxx   10xx xxxx
                char2 = array[i++];
                out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
                break;
            case 14:
                // 1110 xxxx  10xx xxxx  10xx xxxx
                char2 = array[i++];
                char3 = array[i++];
                out += String.fromCharCode(((c & 0x0F) << 12) |
                    ((char2 & 0x3F) << 6) |
                    ((char3 & 0x3F) << 0));
                break;
        }
    }

    return out;
}


// String.prototype.to = function () {
//     let arguments;
//     let str = this.toString();
//     if (arguments.length <= 0) {
//         //如果任何时候都需要使用JSON修改这儿
//         return str;
//     } else if (arguments.length > 0) {
//         return {protype: arguments[0], msg: str, data: arguments[1]};
//     }
// };


let _exports_ = {
    newObj,
    loadObject,
    objectp,
    uint8ArrayToString,
}





